﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using BrainTechLLC.ThreadSafeObjects;
using System.Reflection;
using System.Diagnostics;

namespace BrainTechLLC
{
    [Serializable]
    public class PluginHelper
    {
        public ThreadSafeLookup<string, AppDomain> LoadedAppDomains = new ThreadSafeLookup<string, AppDomain>();

        public void LoadPlugins(string basePath)
        {
            string path = basePath + "plugins" + System.IO.Path.DirectorySeparatorChar;
            string[] files = System.IO.Directory.GetFiles(path);
            Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();

            foreach (string f in files)
            {
                try
                {
                    string fileName = System.IO.Path.GetFileName(f);

                    if (!fileName.EndsWith(".dll"))
                        continue;

                    bool foundIt = false;
                    for (int a = 0; a < asms.Length; a++)
                    {
                        if (asms[a].FullName.IndexOf(fileName, StringComparison.OrdinalIgnoreCase) >= 0)
                        {
                            foundIt = true;
                            break;
                        }
                    }
                    if (!foundIt)
                    {
                        AppDomainSetup setup = new AppDomainSetup()
                        {
                            ShadowCopyFiles = "true"
                        };
                        System.AppDomain domain = System.AppDomain.CreateDomain(fileName, null, setup);
                        domain.DomainUnload += new EventHandler(domain_DomainUnload);
                        domain.UnhandledException += new UnhandledExceptionEventHandler(domain_UnhandledException);
                        System.IO.StreamReader reader = new System.IO.StreamReader(f, System.Text.Encoding.GetEncoding(1252), false);

                        byte[] b = new byte[reader.BaseStream.Length];
                        reader.BaseStream.Read(b, 0, System.Convert.ToInt32(reader.BaseStream.Length));

                        domain.Load(b);
                        System.Reflection.Assembly[] a = domain.GetAssemblies();
                        int index = 0;
                        bool found = false;

                        for (int x = 0; x < a.Length; x++)
                        {
                            if (a[x].GetName().Name + ".dll" == fileName)
                            {
                                index = x;
                                found = true;
                                break;
                            }
                        }

                        if (found)
                        {
                            string dllName = a[index].GetName().Name + ".dll";
                            string dllVersion = a[index].GetName().Version.ToString();
                            string dllSize = reader.BaseStream.Length.ToString();

                            reader.Close();
                            LoadedAppDomains.Add(fileName, domain);
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                    Debug.WriteLine(e.ToString());
                    // throw;
                }
            }
        }

        void domain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Debug.WriteLine("Unhandled exception: " + e.ExceptionObject.ToString());
            Console.WriteLine("Unhandled exception: " + e.ExceptionObject.ToString());
        }

        void domain_DomainUnload(object sender, EventArgs e)
        {
            Debug.WriteLine("Unloaded domain.");
            Console.WriteLine("Unloaded domain.");
        }

        void domain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
        {
            Console.WriteLine("Loaded assembly " + args.LoadedAssembly.FullName);
        }

        //System.Reflection.Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
        //{
        //    Console.WriteLine("Resolved assembly " + args.Name);
        //}

        public void UnloadDomain(string basePath, string name)
        {
            try
            {
                if (System.IO.File.Exists(basePath + "plugins" + System.IO.Path.DirectorySeparatorChar + name))
                {
                    System.AppDomain.Unload((System.AppDomain)LoadedAppDomains[name]);
                    LoadedAppDomains.Remove(name);
                    System.IO.File.Delete(basePath + "plugins" + System.IO.Path.DirectorySeparatorChar + name);
                }
            }
            catch (Exception) { throw; }
        }
    }
}
